#include <iostream>
#include <vector>
#include <cstring>
#include <openssl/evp.h>
#include <openssl/rand.h>

void handleErrors(void) {
    ERR_print_errors_fp(stderr);
    abort();
}

std::vector<unsigned char> aes_encrypt(const std::vector<unsigned char>& plaintext, const std::vector<unsigned char>& key, const std::vector<unsigned char>& iv) {
    EVP_CIPHER_CTX* ctx = EVP_CIPHER_CTX_new();
    if (!ctx) handleErrors();

    if (1 != EVP_EncryptInit_ex(ctx, EVP_aes_128_cbc(), NULL, key.data(), iv.data())) handleErrors();

    std::vector<unsigned char> ciphertext(plaintext.size() + EVP_CIPHER_block_size(EVP_aes_128_cbc()));
    int len;
    if (1 != EVP_EncryptUpdate(ctx, ciphertext.data(), &len, plaintext.data(), plaintext.size())) handleErrors();
    int ciphertext_len = len;

    if (1 != EVP_EncryptFinal_ex(ctx, ciphertext.data() + len, &len)) handleErrors();
    ciphertext_len += len;

    EVP_CIPHER_CTX_cleanup(ctx);
    EVP_CIPHER_CTX_free(ctx);
    ciphertext.resize(ciphertext_len);
    return ciphertext;
}

std::vector<unsigned char> aes_decrypt(const std::vector<unsigned char>& ciphertext, const std::vector<unsigned char>& key, const std::vector<unsigned char>& iv) {
    EVP_CIPHER_CTX* ctx = EVP_CIPHER_CTX_new();
    if (!ctx) handleErrors();

    if (1 != EVP_DecryptInit_ex(ctx, EVP_aes_128_cbc(), NULL, key.data(), iv.data())) handleErrors();

    std::vector<unsigned char> plaintext(ciphertext.size());
    int len;
    if (1 != EVP_DecryptUpdate(ctx, plaintext.data(), &len, ciphertext.data(), ciphertext.size())) handleErrors();
    int plaintext_len = len;

    if (1 != EVP_DecryptFinal_ex(ctx, plaintext.data() + len, &len)) handleErrors();
    plaintext_len += len;

    EVP_CIPHER_CTX_cleanup(ctx);
    EVP_CIPHER_CTX_free(ctx);
    plaintext.resize(plaintext_len);
    return plaintext;
}

int main() {
    // 初始化OpenSSL库
    OpenSSL_add_all_algorithms();
    // ERR_load_crypto_strings();

    // 设置密钥和IV
    std::vector<unsigned char> key(16); // 128位密钥
    std::vector<unsigned char> iv(EVP_MAX_IV_LENGTH);  // 128位IV
    if (!RAND_bytes(key.data(), key.size())) handleErrors();
    if (!RAND_bytes(iv.data(), iv.size())) handleErrors();

    // 原始数据
    std::string plaintext_str = "Hello, OpenSSL AES-128!";
    std::vector<unsigned char> plaintext(plaintext_str.begin(), plaintext_str.end());

    // 加密
    std::vector<unsigned char> ciphertext = aes_encrypt(plaintext, key, iv);
    std::cout << "Ciphertext: ";
    for (unsigned char c : ciphertext) {
        std::cout << std::hex << (int)c;
    }
    std::cout << std::endl;

    BIO_dump_fp(stdout, ciphertext.data(), ciphertext.size());

    // 解密
    std::vector<unsigned char> decryptedtext = aes_decrypt(ciphertext, key, iv);
    std::string decrypted_str(decryptedtext.begin(), decryptedtext.end());
    std::cout << "Decrypted text: " << decrypted_str << std::endl;

    // 清理OpenSSL库
    EVP_cleanup();
    // ERR_free_strings();

    return 0;
}
